<html lang="zh-CN"><head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>高德地图文件加解密工具</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        danger: '#EF4444',
                        dark: '#1E293B',
                        light: '#F8FAFC'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .btn-primary {
                @apply bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-primary/50;
            }
            .btn-secondary {
                @apply bg-secondary hover:bg-secondary/90 text-white font-medium py-2 px-4 rounded-lg transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-secondary/50;
            }
            .btn-danger {
                @apply bg-danger hover:bg-danger/90 text-white font-medium py-2 px-4 rounded-lg transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-danger/50;
            }
            .btn-disabled {
                @apply bg-gray-400 text-gray-700 cursor-not-allowed hover:scale-100;
            }
            .card {
                @apply bg-white rounded-xl shadow-lg p-6 mb-6 transition-all duration-300 hover:shadow-xl;
            }
            .disclaimer {
                @apply fixed inset-0 bg-black/70 z-50 flex items-center justify-center p-4;
            }
            .disclaimer-content {
                @apply bg-white rounded-xl p-6 max-w-md w-full transform transition-all duration-300 scale-100;
            }
            .file-drop-area {
                @apply relative border-2 border-dashed border-gray-300 rounded-lg p-6 text-center transition-all duration-200;
            }
            .file-drop-area.active {
                @apply border-primary bg-primary/5;
            }
            .file-drop-icon {
                @apply text-gray-400 text-3xl mb-2;
            }
            .file-drop-text {
                @apply text-gray-600 mb-2;
            }
            .delete-btn {
                @apply text-danger hover:text-danger/80 transition-colors duration-200 cursor-pointer;
            }
        }
    </style>
</head>
<body class="bg-gray-100 min-h-screen font-sans">
    <!-- 免责声明弹窗 -->
    <div id="disclaimerDialog" class="disclaimer">
        <div class="disclaimer-content">
            <h3 class="text-xl font-bold text-dark mb-4">免责声明</h3>
            <p class="text-gray-700 mb-6">By西瓜君提示：本工具仅供学习研究使用，请遵守相关法律法规</p>
            <button id="closeDisclaimer" class="btn-primary w-full">我已了解</button>
        </div>
    </div>

    <div class="container mx-auto px-4 py-8 max-w-4xl">
        <!-- 标题 -->
        <div class="text-center mb-8">
            <h1 class="text-[clamp(1.8rem,5vw,2.5rem)] font-bold text-dark mb-2">高德车机版地图文件加解密工具</h1>
            <p class="text-gray-600">支持高德7.5及以下和8.1及以上版本文件处理</p>
        </div>

        <!-- 状态卡片 -->
        <div class="card">
            <div class="flex items-center mb-4">
                <i class="fa fa-info-circle text-primary mr-2"></i>
                <h2 class="text-lg font-semibold text-dark">状态信息</h2>
            </div>
            <div class="border-t border-gray-200 pt-4">
                <p id="statusText" class="text-gray-700 mb-4">状态: 请上传文件</p>
                
                <!-- 进度条 -->
                <div id="progressContainer" class="hidden mb-4">
                    <div class="flex justify-between text-sm mb-1">
                        <span class="text-gray-600">处理进度</span>
                        <span id="progressPercent" class="text-gray-600 font-medium">0%</span>
                    </div>
                    <div class="w-full bg-gray-200 rounded-full h-2.5">
                        <div id="progressBar" class="bg-primary h-2.5 rounded-full" style="width: 0%"></div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 文件选择和权限部分 -->
        <div class="card">
            <div class="flex items-center mb-4">
                <i class="fa fa-folder-open text-primary mr-2"></i>
                <h2 class="text-lg font-semibold text-dark">文件操作</h2>
            </div>
            <div class="border-t border-gray-200 pt-4">
                <!-- 文件拖放区域 -->
                <div id="fileDropArea" class="file-drop-area mb-4">
                    <input type="file" id="fileInput" class="hidden" multiple="">
                    
                    <div class="file-drop-icon">
                        <i class="fa fa-cloud-upload"></i>
                    </div>
                    
                    <div class="file-drop-text">
                        <p class="mb-1">拖放文件到此处，或</p>
                        <button id="browseFiles" class="text-primary hover:text-primary/80 font-medium">
                            <i class="fa fa-folder-open mr-1"></i> 浏览文件
                        </button>
                    </div>
                    
                    <p class="text-xs text-gray-500 mt-2">支持拖放多个文件</p>
                </div>
                
                <div id="selectedFiles" class="mb-4 hidden">
                    <div class="flex justify-between items-center mb-2">
                        <h3 class="text-sm font-medium text-gray-700">已选择的文件:</h3>
                        <button id="resetFiles" class="text-xs text-primary hover:text-primary/80 font-medium">
                            <i class="fa fa-refresh mr-1"></i> 重置选择
                        </button>
                    </div>
                    <ul id="fileList" class="text-sm text-gray-600 space-y-1"></ul>
                </div>
                
                <div id="permissionRequired" class="mb-4 p-3 bg-yellow-50 border-l-4 border-yellow-400 rounded">
                    <div class="flex">
                        <div class="flex-shrink-0">
                            <i class="fa fa-exclamation-triangle text-yellow-500"></i>
                        </div>
                        <div class="ml-3">
                            <p class="text-sm text-yellow-700">
                                需要允许文件访问权限才能处理文件
                            </p>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 操作按钮 -->
        <div class="card">
            <div class="flex items-center mb-4">
                <i class="fa fa-cogs text-primary mr-2"></i>
                <h2 class="text-lg font-semibold text-dark">操作选项</h2>
            </div>
            <div class="border-t border-gray-200 pt-4">
                <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <button id="btnDecrypt75" class="btn-primary flex items-center justify-center">
                        <i class="fa fa-unlock-alt mr-2"></i> 解密7.5版本
                    </button>
                    <button id="btnEncrypt75" class="btn-secondary flex items-center justify-center">
                        <i class="fa fa-lock mr-2"></i> 加密7.5版本
                    </button>
                    <button id="btnDecrypt81" class="btn-primary flex items-center justify-center">
                        <i class="fa fa-unlock-alt mr-2"></i> 解密8.1版本
                    </button>
                    <button id="btnEncrypt81" class="btn-secondary flex items-center justify-center">
                        <i class="fa fa-lock mr-2"></i> 加密8.1版本
                    </button>
                </div>
            </div>
        </div>

        <!-- 操作日志 -->
        <div class="card">
            <div class="flex items-center mb-4">
                <i class="fa fa-history text-primary mr-2"></i>
                <h2 class="text-lg font-semibold text-dark">操作日志</h2>
            </div>
            <div class="border-t border-gray-200 pt-4">
                <div id="logContainer" class="bg-gray-50 rounded-lg p-3 h-40 overflow-y-auto text-sm text-gray-700">
                    <p class="text-gray-500">等待操作...</p>
                </div>
            </div>
        </div>
    </div>

    <footer class="bg-dark text-white py-6 mt-8">
        <div class="container mx-auto px-4 text-center">
            <p class="mb-2">高德车机版地图文件加解密工具</p>
            <p class="text-gray-400 text-sm">本工具仅供学习研究使用&nbsp;一切后果自行承担</p>
        </div>
    </footer>

    <script>
        // 常量定义
        const ALGORITHM = "AES/CBC/PKCS7Padding"; // CryptoJS使用PKCS7Padding
        const BLOCK_SIZE = 16;
        
        // 7.5版本密钥
        const KEY_75 = "Jbga21autoj7ZAsF";
        const IV_75 = "1dad13fda3f13g5e";
        
        // 8.1版本密钥
        const KEY_81 = "Yqwr31autou4PbNM";
        const IV_81 = "1dad13fda3f13g5e";
        
        // DOM元素
        const disclaimerDialog = document.getElementById('disclaimerDialog');
        const closeDisclaimer = document.getElementById('closeDisclaimer');
        const statusText = document.getElementById('statusText');
        const progressContainer = document.getElementById('progressContainer');
        const progressBar = document.getElementById('progressBar');
        const progressPercent = document.getElementById('progressPercent');
        const fileInput = document.getElementById('fileInput');
        const fileDropArea = document.getElementById('fileDropArea');
        const browseFiles = document.getElementById('browseFiles');
        const selectedFiles = document.getElementById('selectedFiles');
        const fileList = document.getElementById('fileList');
        const permissionRequired = document.getElementById('permissionRequired');
        const btnDecrypt75 = document.getElementById('btnDecrypt75');
        const btnEncrypt75 = document.getElementById('btnEncrypt75');
        const btnDecrypt81 = document.getElementById('btnDecrypt81');
        const btnEncrypt81 = document.getElementById('btnEncrypt81');
        const logContainer = document.getElementById('logContainer');
        const resetFiles = document.getElementById('resetFiles');
        
        // 状态变量
        let selectedFilesData = [];
        let isProcessing = false;
        let totalFiles = 0;
        let processedFiles = 0;
        
        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 检查文件权限
            checkFilePermissions();
            
            // 关闭免责声明
            closeDisclaimer.addEventListener('click', function() {
                disclaimerDialog.classList.add('opacity-0', 'pointer-events-none');
                setTimeout(() => {
                    disclaimerDialog.classList.add('hidden');
                }, 300);
            });
            
            // 文件选择事件
            fileInput.addEventListener('change', handleFileSelection);
            
            // 浏览文件按钮
            browseFiles.addEventListener('click', () => {
                fileInput.click();
            });
            
            // 拖放事件
            setupDragDrop();
            
            // 按钮事件
            btnDecrypt75.addEventListener('click', () => processFiles(1, 75));
            btnEncrypt75.addEventListener('click', () => processFiles(2, 75));
            btnDecrypt81.addEventListener('click', () => processFiles(1, 81));
            btnEncrypt81.addEventListener('click', () => processFiles(2, 81));
            
            // 重置文件选择
            resetFiles.addEventListener('click', resetFileSelection);
            
            // 默认禁用按钮
            disableCryptoButtons();
            
            // 添加日志
            addLog("工具已初始化，请选择文件并授予权限");
        });
        
        // 设置拖放功能
        function setupDragDrop() {
            // 阻止默认的拖放行为
            ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
                fileDropArea.addEventListener(eventName, preventDefaults, false);
                document.body.addEventListener(eventName, preventDefaults, false);
            });
            
            function preventDefaults(e) {
                e.preventDefault();
                e.stopPropagation();
            }
            
            // 高亮拖放区域
            ['dragenter', 'dragover'].forEach(eventName => {
                fileDropArea.addEventListener(eventName, highlight, false);
            });
            
            ['dragleave', 'drop'].forEach(eventName => {
                fileDropArea.addEventListener(eventName, unhighlight, false);
            });
            
            function highlight() {
                fileDropArea.classList.add('active');
            }
            
            function unhighlight() {
                fileDropArea.classList.remove('active');
            }
            
            // 处理拖放文件
            fileDropArea.addEventListener('drop', handleDrop, false);
            
            function handleDrop(e) {
                const dt = e.dataTransfer;
                const files = dt.files;
                
                if (files.length > 0) {
                    handleFileSelection({ target: { files } });
                }
            }
        }
        
        // 检查文件权限
        function checkFilePermissions() {
            // 浏览器中无法直接检查文件权限，但可以检测文件API支持
            if (typeof window.FileReader === 'undefined') {
                statusText.textContent = "状态: 您的浏览器不支持文件操作";
                permissionRequired.innerHTML = `
                    <div class="flex">
                        <div class="flex-shrink-0">
                            <i class="fa fa-exclamation-circle text-red-500"></i>
                        </div>
                        <div class="ml-3">
                            <p class="text-sm text-red-700">
                                您的浏览器不支持文件API，请使用现代浏览器
                            </p>
                        </div>
                    </div>
                `;
                disableCryptoButtons();
            } else {
                statusText.textContent = "状态: 已准备好，请选择文件";
                permissionRequired.classList.add('hidden');
                updateButtonState();
            }
        }
        
        // 处理文件选择
        function handleFileSelection(event) {
            const files = event.target.files;
            if (files.length === 0) {
                selectedFiles.classList.add('hidden');
                selectedFilesData = [];
                statusText.textContent = "状态: 未选择文件";
                updateButtonState();
                return;
            }
            
            // 合并已选文件和新选文件
            const newFiles = Array.from(files);
            const uniqueFiles = [...new Set([...selectedFilesData, ...newFiles])];
            
            // 检查是否有重复文件名
            const fileNames = new Set();
            const filteredFiles = uniqueFiles.filter(file => {
                if (fileNames.has(file.name)) {
                    addLog(`警告: 已跳过重复文件 - ${file.name}`);
                    return false;
                }
                fileNames.add(file.name);
                return true;
            });
            
            selectedFilesData = filteredFiles;
            statusText.textContent = `状态: 已选择 ${selectedFilesData.length} 个文件`;
            
            // 显示文件列表
            renderFileList();
            
            // 检查可用的文件对数量
            checkFilePairs();
            
            selectedFiles.classList.remove('hidden');
            updateButtonState();
            
            addLog(`已添加 ${files.length} 个文件，总共 ${selectedFilesData.length} 个文件`);
        }
        
        // 渲染文件列表
        function renderFileList() {
            fileList.innerHTML = '';
            selectedFilesData.forEach((file, index) => {
                const listItem = document.createElement('li');
                listItem.className = 'flex items-center justify-between';
                listItem.innerHTML = `
                    <div class="flex items-center">
                        <i class="fa fa-file-o text-gray-400 mr-2"></i>
                        <span>${file.name}</span>
                    </div>
                    <div class="flex items-center">
                        <span class="ml-4 text-xs text-gray-500">${formatFileSize(file.size)}</span>
                        <button class="delete-btn ml-2" data-index="${index}">
                            <i class="fa fa-times-circle"></i>
                        </button>
                    </div>
                `;
                
                // 添加删除按钮事件
                const deleteBtn = listItem.querySelector('.delete-btn');
                deleteBtn.addEventListener('click', (e) => {
                    e.stopPropagation();
                    const fileIndex = parseInt(e.currentTarget.dataset.index);
                    removeFile(fileIndex);
                });
                
                fileList.appendChild(listItem);
            });
        }
        
        // 移除文件
        function removeFile(index) {
            if (index >= 0 && index < selectedFilesData.length) {
                const removedFile = selectedFilesData.splice(index, 1)[0];
                addLog(`已移除文件: ${removedFile.name}`);
                
                if (selectedFilesData.length === 0) {
                    selectedFiles.classList.add('hidden');
                    statusText.textContent = "状态: 未选择文件";
                } else {
                    statusText.textContent = `状态: 已选择 ${selectedFilesData.length} 个文件`;
                    renderFileList();
                    checkFilePairs();
                }
                
                updateButtonState();
            }
        }
        
        // 重置文件选择
        function resetFileSelection() {
            selectedFilesData = [];
            selectedFiles.classList.add('hidden');
            statusText.textContent = "状态: 未选择文件";
            addLog("已重置文件选择");
            updateButtonState();
        }
        
        // 检查可用的文件对
        function checkFilePairs() {
            const aFiles = selectedFilesData.filter(file => 
                file.name.toLowerCase().endsWith('_a.txt')
            );
            
            // 创建一个映射表，记录每个_a.txt文件对应的_b.txt文件是否存在
            const filePairsMap = new Map();
            
            aFiles.forEach(aFile => {
                // 使用更健壮的正则表达式提取基础名称
                const baseNameMatch = aFile.name.match(/^(.*?)_a\.txt$/i);
                if (!baseNameMatch) {
                    addLog(`✗ 无法解析文件名: ${aFile.name}`);
                    return;
                }
                
                const baseName = baseNameMatch[1];
                
                // 查找匹配的_b.txt文件，不区分大小写
                const hasPair = selectedFilesData.some(file => {
                    const bFileBaseMatch = file.name.match(/^(.*?)_b\.txt$/i);
                    return bFileBaseMatch && bFileBaseMatch[1].toLowerCase() === baseName.toLowerCase();
                });
                
                filePairsMap.set(aFile.name, hasPair);
                
                // 添加详细日志
                if (hasPair) {
                    addLog(`✓ 找到匹配的文件对: ${aFile.name} 和 ${baseName}_b.txt`);
                } else {
                    addLog(`✗ 未找到匹配的文件对: ${aFile.name} (期望: ${baseName}_b.txt)`);
                }
            });
            
            const validPairs = Array.from(filePairsMap.values()).filter(Boolean).length;
            
            if (validPairs > 0) {
                addLog(`共找到 ${validPairs} 对可用的加密文件`);
            } else {
                addLog(`未找到完整的加密文件对，请确保同时选择了_a.txt和_b.txt文件`);
            }
            
            // 保存文件对映射表，供后续处理使用
            window.filePairsMap = filePairsMap;
        }
        
        // 更新按钮状态
        function updateButtonState() {
            if (selectedFilesData.length > 0 && !isProcessing) {
                enableCryptoButtons();
            } else {
                disableCryptoButtons();
            }
        }
        
        // 启用加密按钮
        function enableCryptoButtons() {
            btnDecrypt75.classList.remove('btn-disabled');
            btnEncrypt75.classList.remove('btn-disabled');
            btnDecrypt81.classList.remove('btn-disabled');
            btnEncrypt81.classList.remove('btn-disabled');
        }
        
        // 禁用加密按钮
        function disableCryptoButtons() {
            btnDecrypt75.classList.add('btn-disabled');
            btnEncrypt75.classList.add('btn-disabled');
            btnDecrypt81.classList.add('btn-disabled');
            btnEncrypt81.classList.add('btn-disabled');
        }
        
        // 处理文件
        function processFiles(operationType, version) {
            if (isProcessing) return;
            if (selectedFilesData.length === 0) {
                addLog("错误: 请先选择文件");
                return;
            }
            
            isProcessing = true;
            disableCryptoButtons();
            
            const operationName = operationType === 1 ? "解密" : "加密";
            const versionName = version === 75 ? "7.5" : "8.1";
            
            statusText.textContent = `状态: 正在准备${operationName}${versionName}版本文件...`;
            progressContainer.classList.remove('hidden');
            progressBar.style.width = '0%';
            progressPercent.textContent = '0%';
            
            totalFiles = selectedFilesData.length;
            processedFiles = 0;
            
            addLog(`开始${operationName}${versionName}版本文件，共${totalFiles}个文件`);
            
            // 过滤文件
            let filteredFiles = [];
            if (operationType === 1) {
                // 解密操作：查找.dat文件
                filteredFiles = selectedFilesData.filter(file => 
                    file.name.toLowerCase().endsWith('.dat')
                );
            } else {
                // 加密操作：查找成对的_a.txt和_b.txt文件
                const aFiles = selectedFilesData.filter(file => 
                    file.name.toLowerCase().endsWith('_a.txt')
                );
                
                // 使用正则表达式优化文件匹配逻辑
                filteredFiles = aFiles.filter(aFile => {
                    const aFileBaseMatch = aFile.name.match(/^(.*?)_a\.txt$/i);
                    if (!aFileBaseMatch) {
                        addLog(`✗ 无法解析文件名: ${aFile.name}`);
                        return false;
                    }
                    
                    const baseName = aFileBaseMatch[1];
                    
                    // 查找匹配的_b.txt文件
                    const matchingBFile = selectedFilesData.find(file => {
                        const bFileBaseMatch = file.name.match(/^(.*?)_b\.txt$/i);
                        return bFileBaseMatch && bFileBaseMatch[1].toLowerCase() === baseName.toLowerCase();
                    });
                    
                    return matchingBFile !== undefined;
                });
                
                // 日志输出，帮助调试
                addLog(`找到 ${filteredFiles.length} 对有效的_a.txt和_b.txt文件`);
                filteredFiles.forEach(file => {
                    addLog(`准备处理文件对: ${file.name}`);
                });
            }
            
            if (filteredFiles.length === 0) {
                statusText.textContent = operationType === 1 ? "状态: 未找到.dat文件" : "状态: 未找到成对的_a.txt和_b.txt文件";
                addLog(operationType === 1 ? "错误: 未找到.dat文件" : "错误: 未找到成对的_a.txt和_b.txt文件");
                
                // 显示所有已选文件，帮助用户排查问题
                if (operationType === 2) {
                    addLog("已选文件列表:");
                    selectedFilesData.forEach(file => {
                        addLog(`- ${file.name}`);
                    });
                }
                
                isProcessing = false;
                progressContainer.classList.add('hidden');
                updateButtonState();
                return;
            }
            
            // 处理文件
            processNextFile(filteredFiles, 0, operationType, version);
        }
        
        // 处理下一个文件
        function processNextFile(files, index, operationType, version) {
            if (index >= files.length) {
                // 所有文件处理完成
                const operationName = operationType === 1 ? "解密" : "加密";
                const versionName = version === 75 ? "7.5" : "8.1";
                
                statusText.textContent = `${versionName}${operationName}完成! 处理文件: ${processedFiles}/${totalFiles}`;
                addLog(`${versionName}${operationName}完成! 成功处理 ${processedFiles} 个文件`);
                
                isProcessing = false;
                progressContainer.classList.add('hidden');
                updateButtonState();
                return;
            }
            
            const file = files[index];
            const operationName = operationType === 1 ? "解密" : "加密";
            const versionName = version === 75 ? "7.5" : "8.1";
            
            statusText.textContent = `状态: 正在${operationName}${versionName}版本文件: ${index+1}/${files.length}`;
            
            try {
                if (operationType === 1) {
                    // 解密操作
                    decryptFile(file, version)
                        .then(() => {
                            processedFiles++;
                            updateProgress();
                            processNextFile(files, index + 1, operationType, version);
                        })
                        .catch(error => {
                            addLog(`错误: 处理文件 ${file.name} 失败 - ${error.message}`);
                            processNextFile(files, index + 1, operationType, version);
                        });
                } else {
                    // 加密操作
                    encryptFile(file, version)
                        .then(() => {
                            processedFiles++;
                            updateProgress();
                            processNextFile(files, index + 1, operationType, version);
                        })
                        .catch(error => {
                            addLog(`错误: 处理文件 ${file.name} 失败 - ${error.message}`);
                            processNextFile(files, index + 1, operationType, version);
                        });
                }
            } catch (error) {
                addLog(`错误: 处理文件 ${file.name} 失败 - ${error.message}`);
                processNextFile(files, index + 1, operationType, version);
            }
        }
        
        // 更新进度
        function updateProgress() {
            const percent = Math.round((processedFiles / totalFiles) * 100);
            progressBar.style.width = `${percent}%`;
            progressPercent.textContent = `${percent}%`;
        }
        
        // 解密文件
        async function decryptFile(file, version) {
            const key = version === 75 ? KEY_75 : KEY_81;
            const iv = version === 75 ? IV_75 : IV_81;
            
            addLog(`开始解密文件: ${file.name}`);
            
            // 读取文件内容
            const fileContent = await readFileAsArrayBuffer(file);
            const encryptedData = CryptoJS.lib.WordArray.create(new Uint8Array(fileContent));
            
            // 解密
            const decrypted = CryptoJS.AES.decrypt(
                { ciphertext: encryptedData },
                CryptoJS.enc.Utf8.parse(key),
                {
                    iv: CryptoJS.enc.Utf8.parse(iv),
                    mode: CryptoJS.mode.CBC,
                    padding: CryptoJS.pad.Pkcs7
                }
            );
            
            const decryptedBytes = decrypted.toString(CryptoJS.enc.Latin1).toString();
            const decryptedArrayBuffer = new ArrayBuffer(decryptedBytes.length);
            const decryptedUint8Array = new Uint8Array(decryptedArrayBuffer);
            
            for (let i = 0; i < decryptedBytes.length; i++) {
                decryptedUint8Array[i] = decryptedBytes.charCodeAt(i);
            }
            
            // 分割数据并保存
            const baseName = file.name.substring(0, file.name.lastIndexOf('.'));
            
            // 前20字节存入_a.txt
            const first20Bytes = decryptedArrayBuffer.slice(0, 20);
            const fileA = new Blob([first20Bytes], { type: 'text/plain' });
            saveFile(fileA, `${baseName}_a.txt`);
            
            // 剩余数据存入_b.txt
            if (decryptedArrayBuffer.byteLength > 20) {
                const remainingBytes = decryptedArrayBuffer.slice(20);
                const fileB = new Blob([remainingBytes], { type: 'text/plain' });
                saveFile(fileB, `${baseName}_b.txt`);
            }
            
            addLog(`成功解密文件: ${file.name} -> ${baseName}_a.txt & ${baseName}_b.txt`);
        }
        
        // 加密文件
        async function encryptFile(file, version) {
            const key = version === 75 ? KEY_75 : KEY_81;
            const iv = version === 75 ? IV_75 : IV_81;
            
            addLog(`开始加密文件对: ${file.name}`);
            
            const baseName = file.name.substring(0, file.name.lastIndexOf('_a.txt'));
            
            // 查找对应的_b.txt文件
            const bFile = selectedFilesData.find(f => {
                const fBaseMatch = f.name.match(/^(.*?)_b\.txt$/i);
                return fBaseMatch && fBaseMatch[1].toLowerCase() === baseName.toLowerCase();
            });
            
            if (!bFile) {
                throw new Error(`未找到对应的_b.txt文件: ${baseName}_b.txt`);
            }
            
            // 读取_a.txt文件
            const aFileContent = await readFileAsArrayBuffer(file);
            const aData = new Uint8Array(aFileContent);
            
            // 读取_b.txt文件
            const bFileContent = await readFileAsArrayBuffer(bFile);
            const bData = new Uint8Array(bFileContent);
            
            // 调试日志
            addLog(`处理文件对: ${file.name} 和 ${bFile.name}`);
            addLog(`_a.txt大小: ${aData.length} 字节`);
            addLog(`_b.txt大小: ${bData.length} 字节`);
            
            // 获取b.txt文件大小并转为16进制
            const bFileSize = bFileContent.byteLength;
            const hexSize = bFileSize.toString(16).padStart(8, '0');
            
            // 将16进制大小倒序
            const hexBytes = new Uint8Array(4);
            for (let i = 0; i < 4; i++) {
                hexBytes[i] = parseInt(hexSize.substring((3 - i) * 2, (3 - i) * 2 + 2), 16);
            }
            
            // 替换a.txt文件的最后4个字节
            if (aData.length >= 4) {
                aData.set(hexBytes, aData.length - 4);
                addLog(`已更新${file.name}的最后4个字节为_b.txt的大小: ${hexSize}`);
            } else {
                addLog(`警告: ${file.name}长度不足4字节，无法更新大小信息`);
            }
            
            // 合并数据
            const mergedData = new Uint8Array(aData.length + bData.length);
            mergedData.set(aData, 0);
            mergedData.set(bData, aData.length);
            
            // 加密
            const encrypted = CryptoJS.AES.encrypt(
                CryptoJS.enc.Latin1.parse(String.fromCharCode.apply(null, mergedData)),
                CryptoJS.enc.Utf8.parse(key),
                {
                    iv: CryptoJS.enc.Utf8.parse(iv),
                    mode: CryptoJS.mode.CBC,
                    padding: CryptoJS.pad.Pkcs7
                }
            );
            
            const encryptedArrayBuffer = new ArrayBuffer(encrypted.ciphertext.sigBytes);
            const encryptedUint8Array = new Uint8Array(encryptedArrayBuffer);
            
            for (let i = 0; i < encrypted.ciphertext.sigBytes; i++) {
                encryptedUint8Array[i] = (encrypted.ciphertext.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
            }
            
            // 创建加密后的文件
            const encryptedFile = new Blob([encryptedArrayBuffer], { type: 'application/octet-stream' });
            saveFile(encryptedFile, `${baseName}.dat`);
            
            addLog(`成功加密文件对: ${file.name} & ${bFile.name} -> ${baseName}.dat`);
        }
        
        // 读取文件为ArrayBuffer
        function readFileAsArrayBuffer(file) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => resolve(reader.result);
                reader.onerror = () => reject(reader.error);
                reader.readAsArrayBuffer(file);
            });
        }
        
        // 保存文件
        function saveFile(blob, fileName) {
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            link.download = fileName;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(link.href);
        }
        
        // 添加日志
        function addLog(message) {
            const logEntry = document.createElement('p');
            logEntry.className = 'mb-1';
            logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
            logContainer.appendChild(logEntry);
            logContainer.scrollTop = logContainer.scrollHeight;
        }
        
        // 格式化文件大小
        function formatFileSize(bytes) {
            if (bytes === 0) return '0 Bytes';
            const k = 1024;
            const sizes = ['Bytes', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }
    </script>

    </body></html>